    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #undef DLIB_BIGINT_KERNEl_ABSTRACT_
    #ifdef DLIB_BIGINT_KERNEl_ABSTRACT_

    #include <iosfwd>
    #include "../algs.h"
    #include "../serialize.h"
    #include "../uintn.h"

    namespace dlib
    {

        class bigint
        {
            /*!
                INITIAL VALUE
                    *this == 0

                WHAT THIS OBJECT REPRESENTS
                    This object represents an arbitrary precision unsigned integer

                    the following operators are supported:
                    operator +
                    operator +=
                    operator -
                    operator -=
                    operator *
                    operator *=
                    operator /
                    operator /=
                    operator %
                    operator %=
                    operator ==
                    operator <
                    operator =
                    operator << (for writing to ostreams)
                    operator >> (for reading from istreams)
                    operator++       // pre increment
                    operator++(int)  // post increment
                    operator--       // pre decrement
                    operator--(int)  // post decrement

                    the other comparison operators(>, !=, <=, and >=) are
                    available and come from the templates in dlib::relational_operators

                THREAD SAFETY
                    bigint may be reference counted so it is very unthread safe.
                    use with care in a multithreaded program

            !*/

        public:

            bigint (
            );
            /*!
                ensures
                    - #*this is properly initialized
                throws
                    - std::bad_alloc
                        if this is thrown the bigint will be unusable but
                        will not leak memory
            !*/

            bigint (
                uint32 value
            );
            /*!
                requires
                    - value <= (2^32)-1
                ensures
                    - #*this is properly initialized
                    - #*this == value
                throws
                    - std::bad_alloc
                        if this is thrown the bigint will be unusable but
                        will not leak memory
            !*/

            bigint (
                const bigint& item
            );
            /*!
                ensures
                    - #*this is properly initialized
                    - #*this == value
                throws
                    - std::bad_alloc
                        if this is thrown the bigint will be unusable but
                        will not leak memory
            !*/

            virtual ~bigint (
            );
            /*!
                ensures
                    - all resources associated with #*this have been released
            !*/

            const bigint operator+ (
                const bigint& rhs
            ) const;
            /*!
                ensures
                    - returns the result of adding rhs to *this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator+= (
                const bigint& rhs
            );
            /*!
                ensures
                    - #*this == *this + rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator- (
                const bigint& rhs
            ) const;
            /*!
                requires
                    - *this >= rhs
                ensures
                    - returns the result of subtracting rhs from *this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator-= (
                const bigint& rhs
            );
            /*!
                requires
                    - *this >= rhs
                ensures
                    - #*this == *this - rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator* (
                const bigint& rhs
            ) const;
            /*!
                ensures
                    - returns the result of multiplying *this and rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator*= (
                const bigint& rhs
            );
            /*!
                ensures
                    - #*this == *this * rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator/ (
                const bigint& rhs
            ) const;
            /*!
                requires
                    - rhs != 0
                ensures
                    - returns the result of dividing *this by rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator/= (
                const bigint& rhs
            );
            /*!
                requires
                    - rhs != 0
                ensures
                    - #*this == *this / rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator% (
                const bigint& rhs
            ) const;
            /*!
                requires
                    - rhs != 0
                ensures
                    - returns the result of *this mod rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator%= (
                const bigint& rhs
            );
            /*!
                requires
                    - rhs != 0
                ensures
                    - #*this == *this % rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bool operator < (
                const bigint& rhs
            ) const;
            /*!
                ensures
                    - returns true if *this is less than rhs
                    - returns false otherwise
            !*/

            bool operator == (
                const bigint& rhs
            ) const;
            /*!
                ensures
                    - returns true if *this and rhs represent the same number
                    - returns false otherwise
            !*/

            bigint& operator= (
                const bigint& rhs
            );
            /*!
                ensures
                    - #*this == rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend std::ostream& operator<< (
                std::ostream& out,
                const bigint& rhs
            );
            /*!
                ensures
                    - the number in *this has been written to #out as a base ten number
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect (nothing
                        is written to out)
            !*/

            friend std::istream& operator>> (
                std::istream& in,
                bigint& rhs
            );
            /*!
                ensures
                    - reads a number from in and puts it into #*this
                    - if (there is no positive base ten number on the input stream ) then
                        - #in.fail() == true
                throws
                    - std::bad_alloc
                        if this function throws the value in rhs is undefined and some
                        characters may have been read from in.  rhs is still usable though,
                        its value is just unknown.
            !*/

            bigint& operator++ (
            );
            /*!
                ensures
                    - #*this == *this + 1
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator++ (
                int
            );
            /*!
                ensures
                    - #*this == *this + 1
                    - returns *this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator-- (
            );
            /*!
                requires
                    - *this != 0
                ensures
                    - #*this == *this - 1
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            const bigint operator-- (
                int
            );
            /*!
                requires
                    - *this != 0
                ensures
                    - #*this == *this - 1
                    - returns *this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            void swap (
                bigint& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/

            // ------------------------------------------------------------------
            // ----    The following functions are identical to the above   -----
            // ----  but take uint16 as one of their arguments. They  ---
            // ----  exist only to allow for a more efficient implementation  ---
            // ------------------------------------------------------------------

            friend const bigint operator+ (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - lhs <= 65535
                ensures
                    - returns the result of adding rhs to lhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator+ (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - returns the result of adding rhs to lhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator+= (
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - #*this == *this + rhs
                    - returns #this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator- (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - lhs >= rhs
                    - lhs <= 65535
                ensures
                    - returns the result of subtracting rhs from lhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator- (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - lhs >= rhs
                    - rhs <= 65535
                ensures
                    - returns the result of subtracting rhs from lhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator-= (
                uint16 rhs
            );
            /*!
                requires
                    - *this >= rhs
                    - rhs <= 65535
                ensures
                    - #*this == *this - rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator* (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - lhs <= 65535
                ensures
                    - returns the result of multiplying lhs and rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator* (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - returns the result of multiplying lhs and rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator*= (
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - #*this == *this * rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator/ (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - rhs != 0
                    - lhs <= 65535
                ensures
                    - returns the result of dividing lhs by rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator/ (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs != 0
                    - rhs <= 65535
                ensures
                    - returns the result of dividing lhs by rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator/= (
                uint16 rhs
            );
            /*!
                requires
                    - rhs != 0
                    - rhs <= 65535
                ensures
                    - #*this == *this / rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator% (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - rhs != 0
                    - lhs <= 65535
                ensures
                    - returns the result of lhs mod rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend const bigint operator% (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs != 0
                    - rhs <= 65535
                ensures
                    - returns the result of lhs mod rhs
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            bigint& operator%= (
                uint16 rhs
            );
            /*!
                requires
                    - rhs != 0
                    - rhs <= 65535
                ensures
                    - #*this == *this % rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

            friend bool operator < (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - lhs <= 65535
                ensures
                    - returns true if lhs is less than rhs
                    - returns false otherwise
            !*/

            friend bool operator < (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - returns true if lhs is less than rhs
                    - returns false otherwise
            !*/

            friend bool operator == (
                const bigint& lhs,
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - returns true if lhs and rhs represent the same number
                    - returns false otherwise
            !*/

            friend bool operator == (
                uint16 lhs,
                const bigint& rhs
            );
            /*!
                requires
                    - lhs <= 65535
                ensures
                    - returns true if lhs and rhs represent the same number
                    - returns false otherwise
            !*/

            bigint& operator= (
                uint16 rhs
            );
            /*!
                requires
                    - rhs <= 65535
                ensures
                    - #*this == rhs
                    - returns #*this
                throws
                    - std::bad_alloc
                        if this function throws then it has no effect
            !*/

        };

        inline void swap (
            bigint& a,
            bigint& b
        ) { a.swap(b); }
        /*!
            provides a global swap function
        !*/

        void serialize (
            const bigint& item,
            std::istream& in
        );
        /*!
            provides serialization support
        !*/

        void deserialize (
            bigint& item,
            std::istream& in
        );
        /*!
            provides deserialization support
        !*/

        inline bool operator>  (const bigint& a, const bigint& b) { return b < a; }
        inline bool operator!= (const bigint& a, const bigint& b) { return !(a == b); }
        inline bool operator<= (const bigint& a, const bigint& b) { return !(b < a); }
        inline bool operator>= (const bigint& a, const bigint& b) { return !(a < b); }
    }

    #endif // DLIB_BIGINT_KERNEl_ABSTRACT_